using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using HengTong.Model;
using HengTong.Model.Db.Hr;
using HengTong.Model.Db.Hr.Attendance;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using TiaoTaoHelper.Wtm.Services;
using UUIDNext;
using WalkingTec.Mvvm.Core.Support.Quartz;

namespace HengTong.Tasks;

/// <summary>
/// 计划排班
/// </summary>
[Display(Name = "计划排班", Description = "计划排班")]
[QuartzRepeat(3600 * 24, 0, true, 0)] // 每天执行一次
public class UpdatePersonAttendanceRecord : BaseTask<UpdatePersonAttendanceRecord>
{
    protected override async Task<bool> ExecuteStart()
    {
        try
        {
            var dc = Wtm.DC;
            //查询在职人员
            var persons = await dc.Set<SysPerson>()
                .AsNoTracking()
                .Where(x => x.GetType() == typeof(SysPerson))
                .Where(e => e.State == PersonState.在职)
                .Select(e => new
                {
                    e.ID,
                    e.Name,
                    e.StaffNo
                })
                .ToListAsync();
            //循环在职人员
            var records = new List<SysAttendanceRecord>();
            foreach (var person in persons)
            {
                //读取人员今天以前最近的一条排班记录(感知到考勤组)
                var lastRecord = await dc.Set<SysAttendanceRecord>()
                    .AsNoTracking()
                    .Where(e => e.PersonId == person.ID)
                    .Where(e => e.ShiftDate < DateOnly.FromDateTime(DateTime.Now))
                    .OrderByDescending(e => e.ShiftDate)
                    .FirstOrDefaultAsync();
                //如果没有排班记录，跳过
                if(lastRecord == null) continue;
                //读取今天以后所有的排班记录
                var futureRecords = await dc.Set<SysAttendanceRecord>()
                    .AsNoTracking()
                    .Where(e => e.PersonId == person.ID)
                    .Where(e => e.ShiftDate >= DateOnly.FromDateTime(DateTime.Now))
                    .OrderBy(e => e.ShiftDate)
                    .ToListAsync();
                //合并排班记录
                var allRecords = new List<SysAttendanceRecord>();
                allRecords.Add(lastRecord);
                allRecords.AddRange(futureRecords);
                //按照日期循环，开始时间是最早的排班记录的日期，结束时间是未来60天
                var startDate = lastRecord.ShiftDate;
                var endDate = DateOnly.FromDateTime(DateTime.Now.AddDays(90));
                var currentDate = startDate;
                var groupId = lastRecord.AttendanceShiftGroupId;
                do
                {
                    //如果当前日期在排班记录中，继续下一个日期
                    var existingRecord = allRecords.FirstOrDefault(e => e.ShiftDate == currentDate);
                    if (existingRecord != null)
                    {
                        currentDate = currentDate.AddDays(1);
                        groupId = existingRecord.AttendanceShiftGroupId;
                        continue;
                    }
                    //如果当前日期不在排班记录中，创建一条新的排班记录
                    var record = new SysAttendanceRecord
                    {
                        ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                        PersonId = person.ID,
                        AttendanceShiftGroupId = groupId,
                        ShiftType = ShiftTypeEnum.正常上班,
                        ScheduleType = ScheduleTypeEnum.自动排班,
                        Status = ShiftStatusEnum.正常,
                        ShiftDate = currentDate,
                        AttendanceResult = AttendanceResultEnum.未计算,
                        IsAbnormal = false
                    };
                    records.Add(record);
                } while (currentDate <= endDate);
                if (records.Any())
                {
                    await dc.Set<SysAttendanceRecord>().AddRangeAsync(records);
                    await dc.SaveChangesAsync();
                }
            }
            return true;
        }
        catch (Exception e)
        {
            Logger.LogError(e, "自动排班时发生错误");
            return false;
        }
    }
}